#ifndef BMPLOADER_H_
#define BMPLOADER_H_

#include <stdio.h>
#include <vector>
#include "fileClass.h"

//this is done with assumption that sizof(short int)=2 and sizof(int)=4 and byte contains 8bit
namespace BitmapFiles{

class BmpLoadError
{
	public:
	  BmpLoadError(char* message_) 
	  {
		  message_m = new char[strlen(message_)+1]; 
		  strcpy(message_m,message_);
	  }
	  ~BmpLoadError() {delete[] message_m;}
	  char* GetMessage(){return message_m;};
	private:
	  char* message_m;
};

class BasePicture
{
  public:
	struct RGBTRIKE
	{
	  unsigned char rgbBlue;// 	- 	specifies the blue part of the color.
	  unsigned char rgbGreen;// 	- 	specifies the green part of the color.
	  unsigned char rgbRed;// 	- 	specifies the red part of the color.
	};	
	BasePicture(int* OriginalImg_,int* MorphedImg_,int Width_ , int Height_):
		Img_m(OriginalImg_),InnerImg_m(MorphedImg_),
		Height_m(Height_),Width_m(Width_),
		nbits_m(32)
		{}//do not want to copy an image for now
	RGBTRIKE GetPixel(int x,int y)
	{RGBTRIKE out_ = {Img_m[x+Width_m*y]&0x0000ff,Img_m[x+Width_m*y]&0x00ff00,Img_m[x+Width_m*y]&0xff0000}; return out_;}
	void MorphPixel(int x,int y,RGBTRIKE pixel_)
	{InnerImg_m[x+Width_m*y] = (pixel_.rgbRed<<16)+(pixel_.rgbGreen<<8)+pixel_.rgbBlue;}
  private:
	int* Img_m;
	int* InnerImg_m;
    int Height_m;
    int Width_m;
	int nbits_m;
};

class RBG24bit
{
public: 
	
	struct RGBQUAD
	{
	  unsigned char rgbBlue;// 	- 	specifies the blue part of the color.
	  unsigned char rgbGreen;// 	- 	specifies the green part of the color.
	  unsigned char rgbRed;// 	- 	specifies the red part of the color.
	  unsigned char rgbReserved;// 	- 	must always be set to zero.
	};

	struct RGBTRIKE
	{
	  unsigned char rgbBlue;// 	- 	specifies the blue part of the color.
	  unsigned char rgbGreen;// 	- 	specifies the green part of the color.
	  unsigned char rgbRed;// 	- 	specifies the red part of the color.
	};
	
	RBG24bit(char* fName_){ReadBMP(fName_);}
    int GetHeight() {return bmpiHeader_m.biHeight;}
    int GetWidth() {return bmpiHeader_m.biWidth;}
    RGBTRIKE GetColor(int x, int y) {return pixels_m[x+bmpiHeader_m.biWidth*(bmpiHeader_m.biWidth-y-1)];}
struct BITMAPFILEHEADER
{
  short bfType;//must always be set to 'BM' to declare that this is a .bmp-file.
  int bfSize;//specifies the size of the file in bytes.
  short bfReserved1;//must always be set to zero.
  short bfReserved2;//must always be set to zero.
  int bfOffBits;//specifies the offset from the beginning of the file to the bitmap data.
  void fill(ClFile& file_)
  {
	  file_.Read(&bfType);file_.Read(&bfSize);file_.Read(&bfReserved1);
	  file_.Read(&bfReserved2);file_.Read(&bfOffBits);
  }  
};

struct BITMAPINFOHEADER
{
  int biSize;//specifies the size of the BITMAPINFOHEADER structure, in bytes.
  int biWidth;//specifies the width of the image, in pixels.
  int biHeight;//specifies the height of the image, in pixels.
  short biPlanes;//specifies the number of planes of the target device, must be set to zero.
  short biBitCount;//specifies the number of bits per pixel.
  int biCompression;//Specifies the type of compression, usually set to zero (no compression).
  int biSizeImage;//specifies the size of the image data, in bytes. If there is no compression, it is valid to set this member to zero.
  int biXPelsPerMeter;//specifies the the horizontal pixels per meter on the designated targer device, usually set to zero.
  int biYPelsPerMeter;//specifies the the vertical pixels per meter on the designated targer device, usually set to zero.
  int biClrUsed;//specifies the number of colors used in the bitmap, if set to zero the number of colors is calculated using the biBitCount member.
  int biClrImportant;//specifies the number of color that are 'important' for the bitmap, if set to zero, all colors are important.
  void fill(ClFile& file_)
  {
	  file_.Read(&biSize);file_.Read(&biWidth);file_.Read(&biHeight);file_.Read(&biPlanes);
	  file_.Read(&biBitCount);file_.Read(&biCompression);file_.Read(&biSizeImage);file_.Read(&biXPelsPerMeter);
	  file_.Read(&biYPelsPerMeter);file_.Read(&biClrUsed);file_.Read(&biClrImportant);
  }
};

void LoadPalette()
{
	throw BmpLoadError("LoadPalette() not done yet\n");
}

//only 24 bit bmps are supported, if someone want other, please do that :-)
void ReadBMP(char* fName_)
{
  try
  {
	ClFile fileToOpen_(fName_,"rb");
	
	bmpHeader_m.fill(fileToOpen_);
	printf("bfType %d\n",bmpHeader_m.bfType); //clean out after debug
	printf("bfSize %d\n",bmpHeader_m.bfSize);
	printf("bfReserved1 %d\n",bmpHeader_m.bfReserved1);
	printf("bfReserved2 %d\n",bmpHeader_m.bfReserved2);
	printf("bfOffBits %d\n\n",bmpHeader_m.bfOffBits);	
	if (bmpHeader_m.bfType != 19778) throw BmpLoadError("not a bmp file\n");//this is magic number
	bmpiHeader_m.fill(fileToOpen_);
	printf("biSize %d\n",bmpiHeader_m.biSize); //clean out after debug
	printf("biWidth %d\n",bmpiHeader_m.biWidth);
	printf("biHeight %d\n",bmpiHeader_m.biHeight);
	printf("biPlanes %d\n",bmpiHeader_m.biPlanes);
	printf("biBitCount %d\n",bmpiHeader_m.biBitCount);
	printf("biCompression %d\n",bmpiHeader_m.biCompression);
	printf("biSizeImage %d\n",bmpiHeader_m.biSizeImage);
	printf("biXPelsPerMeter %d\n",bmpiHeader_m.biXPelsPerMeter);
	printf("biYPelsPerMeter %d\n",bmpiHeader_m.biYPelsPerMeter);
	printf("biClrUsed %d\n",bmpiHeader_m.biClrUsed);
	printf("biClrImportant %d\n",bmpiHeader_m.biClrImportant);
	if (bmpiHeader_m.biBitCount != 24) throw BmpLoadError("24bit only\n");
	
	pixels_m.resize(bmpiHeader_m.biWidth*bmpiHeader_m.biHeight);
	
	for (int i=0;i<bmpiHeader_m.biWidth*bmpiHeader_m.biHeight;i++)
	{
		RGBTRIKE pixel;
		fileToOpen_.Read(&pixel.rgbBlue);fileToOpen_.Read(&pixel.rgbGreen);fileToOpen_.Read(&pixel.rgbRed);
		pixels_m[i]=pixel;
	}
	printf("bmp file %s loaded\n",fName_);
  }
  catch (BmpLoadError message)
  {
	printf(message.GetMessage());
  }	
  catch (...)
  {
	printf("hello there, this is error\n");
  }	  
}
private:
	RGBQUAD Palette_m[256];
	BITMAPFILEHEADER bmpHeader_m;
	BITMAPINFOHEADER bmpiHeader_m;
	std::vector<RGBTRIKE> pixels_m;
};

}
#endif /*BMPLOADER_H_*/
